/**
 *******************************************************************************
 * @file  system_hc32f160.c
 * @brief This file provides two functions and one global variable to be called
 *        from  user application
 @verbatim
   Change Logs:
   Date             Author          Notes
   2020-11-27       CDT             First version
 @endverbatim
 *******************************************************************************
 * Copyright (C) 2020, Huada Semiconductor Co., Ltd. All rights reserved.
 *
 * This software component is licensed by HDSC under BSD 3-Clause license
 * (the "License"); You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                    opensource.org/licenses/BSD-3-Clause
 *
 *******************************************************************************
 */

/*******************************************************************************
 * Include files
 ******************************************************************************/
#include "hc32_common.h"

/**
 * @addtogroup CMSIS
 * @{
 */

/**
 * @addtogroup HC32F160_System
 * @{
 */

/*******************************************************************************
 * Global pre-processor symbols/macros ('define')
 ******************************************************************************/
/*!< Uncomment the following line if you need to relocate your vector Table in
     Internal SRAM. */
/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET                 (0x1000UL)  /*!< Vector Table base offset field.
                                                         This value must be a multiple of 0x100. */

/*******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/
/**
 * @addtogroup HC32F160_System_Global_Variable
 * @{
 */

/*!< System clock frequency (Core clock) */
__NO_INIT uint32_t SystemCoreClock;
/*!< High speed RC frequency (HCR clock) */
__NO_INIT uint32_t HRC_VALUE;

/**
 * @}
 */

/*******************************************************************************
 * Local variable definitions ('static')
 ******************************************************************************/

/*******************************************************************************
 * Function implementation - global ('extern') and local ('static')
 ******************************************************************************/
/**
 * @addtogroup HC32F160_System_Global_Functions
 * @{
 */

/**
 * @brief  Setup the microcontroller system. Initialize the System and update
 *         the SystemCoreClock variable.
 * @param  None
 * @retval None
 */
void SystemInit(void)
{
    SystemCoreClockUpdate();
    /* Configure the Vector Table relocation */
#ifdef VECT_TAB_SRAM
    SCB->VTOR = SRAM_BASE  | VECT_TAB_OFFSET;   /* Vector Table Relocation in Internal SRAM. */
#else
    SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;   /* Vector Table Relocation in Internal FLASH. */
#endif
}

/**
 * @brief  Update HRC frequency according to Clock Register Values.
 * @param  None
 * @retval HRC frequency
 */
static uint32_t HrcUpdate(void)
{
    uint8_t u8HrcDiv;
    uint32_t u32HrcVal = HRC_64MHz_VALUE;

    if ((CM_EFM->CMU_HRCCFGR & EFM_CMU_HRCCFGR_HRCFREQS_3) == EFM_CMU_HRCCFGR_HRCFREQS_3)
    {
        u32HrcVal = HRC_48MHz_VALUE;
    }

    u8HrcDiv = CM_EFM->CMU_HRCCFGR & (~EFM_CMU_HRCCFGR_HRCFREQS_3);
    u32HrcVal = (u8HrcDiv < 5U) ? (u32HrcVal >> u8HrcDiv) : (u32HrcVal >> 5U);

    return u32HrcVal;
}

/**
 * @brief  Update SystemCoreClock variable according to Clock Register Values.
 * @param  None
 * @retval None
 */
void SystemCoreClockUpdate(void)
{
    uint8_t u8SysClkSrc;
    uint8_t u8SysClkDiv;

    u8SysClkSrc = CM_CMU->CKSWR & CMU_CKSWR_CKSW;

    switch(u8SysClkSrc)
    {
        case 0x00U:     /* use internal high speed RC */
            HRC_VALUE = HrcUpdate();
            SystemCoreClock = HRC_VALUE;
            break;
        case 0x01U:     /* use external high speed OSC */
            SystemCoreClock = XTAL_VALUE;
            break;
        case 0x02U:     /* use internal low speed RC */
            SystemCoreClock = LRC_VALUE;
            break;
        case 0x03U:     /* use external low speed OSC */
            SystemCoreClock = XTAL32_VALUE;
            break;
        default:
            break;
    }

    u8SysClkDiv = CM_CMU->SCKDIVR & CMU_SCKDIVR_SCKDIV;
    SystemCoreClock  >>= u8SysClkDiv;
}

#if defined (__CC_ARM) || defined (__CLANG_ARM)
extern int32_t $Super$$main(void);
/* re-define main function */
int $Sub$$main(void)
{
    SystemCoreClockUpdate();
    $Super$$main();
    return 0;
}
#endif

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */

/*******************************************************************************
 * EOF (not truncated)
 ******************************************************************************/
